package org.starti.metadata.impl;

import org.starti.metadata.Metadata;
import org.starti.metadata.MetadataFactory;
import org.starti.metadata.MetadataManager;
import org.starti.metadata.exception.NoMetadataFoundException;

import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Default implementation of MetadataManager.
 * This use a simple cache for improving access performance.
 *
 * @author <a href="mailto:claudiu.dumitrescu@gmail.com">Claudiu Dumitrescu</a>
 */
public class StartiMetadataManager implements MetadataManager {

    /**
     * Poor man cache :)
     */
    private Map<AnnotatedElement, Metadata> cache = new HashMap<AnnotatedElement, Metadata>();

    private Set<Class> types;

    private MetadataFactory metadataFactory;


    public MetadataFactory getMetadataFactory() {
        return metadataFactory;
    }

    public void setMetadataFactory(MetadataFactory metadataFactory) {
        this.metadataFactory = metadataFactory;
    }

    public Set<Class> getTypes() {
        return types;
    }

    public void setTypes(Set<Class> types) {
        this.types = types;
    }

    /**
     * Initialize the Metadata Manager.
     */
    public void initMetadataManager() throws Exception {
        for (Class clazz : types) {
            Metadata metadata = cache.get(clazz);
            if (metadata == null) {
                metadata = metadataFactory.createClass(clazz);
//                for (MetadataProvider provider : metadataFactory.getProviders()) {
//                    if (provider.supports(clazz)) {
//                        BeanUtils.copyProperties(provider.getClassMetadata(clazz), metadata);
//                    }
//                }
                cache.put(clazz, metadata);
            }
            for (Method method : metadata.getProperties()) {
                Metadata metadataProperty = cache.get(method);
                if (metadataProperty == null) {
                    metadataProperty = metadataFactory.createProperty(method);
//                    for (MetadataProvider provider : metadataFactory.getProviders()) {
//                        BeanUtils.copyProperties(provider.getPropertyMetadata(method), metadataProperty);
//                    }
                    cache.put(method, metadataProperty);
                }
            }
        }
    }

    /**
     * Get a Metadata object for a given runtime Class, Method, Property.
     *
     * @return Metadata created
     * @throws org.starti.metadata.exception.NoMetadataFoundException
     *          if <code>element</code> is not known
     */
    public Metadata getMetadata(AnnotatedElement element) throws NoMetadataFoundException {
        return cache.get(element);
    }
}
